<?php
require_once "User.php";
class Group implements arrayaccess
{
	//Version
	const VERSION = 'trunk';

	//Flags
	const GET_BY_ID = 0;
	const GET_BY_NAME = 1;

	//Class Variables
	protected $id = NULL;
	protected $name = NULL;
	protected $members = NULL;

	public function __construct ($gid, $getType = Group::GET_BY_ID)
	{
		$db = new PDO ('sqlite:' . User::config('db_path'));
		if ($getType == Group::GET_BY_ID)
		{
			if(!is_int($gid))
				throw new InvalidArgumentException('Group class constructor expected integer, value given was: '.$gid);
			$query = $db->prepare ("SELECT * FROM groups WHERE id = :id");
			$query->bindValue (":id", $gid, PDO::PARAM_INT);
		}
		else if ($getType == Group::GET_BY_NAME)
		{
			if(!Group::validateGroupname($gid))
				throw new InvalidArgumentException('Groupname is not valid.');
			$query = $db->prepare ("SELECT * FROM groups WHERE name = :name");
			$query->bindValue (":name", $gid, PDO::PARAM_STR);
		}
		else
			throw new OutOfBoundsException('Invalid getType constant: '.$getType);
		$query->execute ();
		$query->bindColumn ("id", $this->id, PDO::PARAM_INT);
		$query->bindColumn ("name", $this->name, PDO::PARAM_STR);
		$query->fetch (PDO::FETCH_BOUND);
		$this->members = $this->getMembers ();
		if($this->id == NULL)
			throw new OutOfBoundsException('No such group found in database: '.$gid);
	}

	public function offsetExists ($user)
	{
		if (is_a ($user, 'User'))
			return $this->isMember ($user);
		return false;
	}

	public function offsetGet ($user)
	{
		if (is_a ($user, 'User'))
			return $this->isMember ($user);
		return false;
	}

	public function offsetSet ($user, $value)
	{
		if ($value)
			$this->addUser ($user);
		else
			$this->delUser ($user);
	}

	public function offsetUnset ($user)
	{
		$this->delUser ($user);
	}

	public function getID ()
	{
		return $this->id;
	}
	
	public function getName ()
	{
		return $this->name;
	}
	
	public function isMember ($user)
	{
		if (!is_a ($user, 'User'))
			throw new InvalidArgumentException ('User object invalid');
		$db = new PDO ('sqlite:' . User::config ('db_path'));
		$query = $db->prepare ("SELECT COUNT (*) FROM groupMemberships WHERE uID = :uID AND gID = :gID");
		$query->bindValue (":uID", $user->getID (), PDO::PARAM_INT);
		$query->bindValue (":gID", $this->getID (), PDO::PARAM_INT);
		$query->execute ();
		if ($query->fetchColumn() > 0)
			return true;
		return false;
	}
	
	public function getMembers ()
	{
		if ($this->members === NULL)
		{
			$db = new PDO ('sqlite:' . User::config ('db_path'));
			$query = $db->prepare ("SELECT uID FROM groupMemberships WHERE gID = :gID");
			$query->bindValue (":gID", $this->getID (), PDO::PARAM_INT);
			$query->execute ();
			$query->bindColumn ('uID', $uid, PDO::PARAM_INT);
			while ($query->fetch (PDO::FETCH_BOUND))
				$this->members[] = $uid;
		}
		return $this->members;
	}
	
	public function addUser ($user)
	{
		if (!is_a ($user, 'User'))
			throw new InvalidArgumentException ('User object invalid');
		if ($this->isMember ($user))
			throw new InvalidArgumentException ('User already in group');
		$db = new PDO ('sqlite:' . User::config ('db_path'));
		$query = $db->prepare ("INSERT INTO groupMemberships (uID, gID) VALUES (:uID, :gID)");
		$query->bindValue (":uID", $user->getID (), PDO::PARAM_INT);
		$query->bindValue (":gID", $this->getID (), PDO::PARAM_INT);
		$query->execute ();
	}
	
	public function delUser ($user)
	{
		if (!is_a ($user, 'User'))
			throw new InvalidArgumentException ('User object invalid');
		if (!$this->isMember ($user))
			throw new InvalidArgumentException ('User not in group');
		$db = new PDO ('sqlite:' . User::config ('db_path'));
		$query = $db->prepare ("DELETE FROM groupMemberships WHERE uID = :uID && gID = :gID");
		$query->bindValue (":uID", $user->getID (), PDO::PARAM_INT);
		$query->bindValue (":gID", $this->getID (), PDO::PARAM_INT);
		$query->execute ();
	}
	
	public static function getGroups ($user)
	{
		if (!is_a ($user, 'User'))
			throw new InvalidArgumentException ('User object invalid');
		$db = new PDO ('sqlite:' . User::config ('db_path'));
		$query = $db->prepare ("SELECT gID FROM groupMemberships WHERE uID = :uID");
		$query->bindValue (":uID", $user->getID (), PDO::PARAM_INT);
		$query->execute ();
		$gIDs = $query->fetchAll ();
//		$groups = array ();
		foreach ($gIDs as $gid)
		{
			$groups[] = new Group ($gid);
		}
		return $groups;
	}
	
	public static function add ($name)
	{
		if (!Group::validateGroupname ($name))
			throw new InvalidArgumentException ('Groupname is not valid.');
		$db = new PDO ('sqlite:' . User::config ('db_path'));
		$query = $db->prepare ("SELECT COUNT (*) FROM groups WHERE name = :name");		
		$query->bindValue (":name", $name, PDO::PARAM_STR);
		$query->execute ();
		if ($query->fetchColumn () > 0)
			throw new InvalidArgumentException ('Groupname already exists.');
		$query = $db->prepare ("INSERT INTO groups (name) VALUES (:name)");
		$query->bindParam (":name", $name, PDO::PARAM_STR);
		$query->execute ();
	}
	
	public static function purgeUser ($user)
	{
		if (!is_a ($user, 'User'))
			throw new InvalidArgumentException ('User object invalid');
		$db = new PDO ('sqlite:' . User::config ('db_path'));
		$query = $db->prepare ("DELETE FROM groupMemberships WHERE uID = :uID");
		$query->bindValue (":uID", $user->getID (), PDO::PARAM_INT);
		$query->execute ();
	}
	
	protected static function validateGroupname($username)
	{
		if(preg_match(User::config('username_regex'), $username))
			return true;
		return false;
	}
	
	public static function setupDB ($db)
	{
//		$db = new PDO ('sqlite:' . User::config('db_path'));
		$db->query ("CREATE TABLE IF NOT EXISTS groups (id INTEGER PRIMARY KEY, name TEXT UNIQUE)");
		$db->query ("CREATE TABLE IF NOT EXISTS groupMemberships (id INTEGER PRIMARY KEY, uID INTEGER, gID INTEGER, FOREIGN KEY (uID) REFERENCES users (id), FOREIGN KEY (gID) REFERENCES groups (id), UNIQUE (uID, gID))");
	}
}



User::addEventHandler('postSetup', 'Group::setupDB');
User::addEventHandler('onRemove', 'Group::purgeUser');
?>
